/*

    Support for "GeoGrid Viewer ascii overlay files".

    Copyright (C) 2008 Olaf Klein (o.b.klein@gpsbabel.org).

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA

 */
 
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#include "defs.h"
#include "inifile.h"
#include "grtcirc.h"

#define MYNAME "ggv_ovl"

static
arglist_t ggv_ovl_args[] = {
	ARG_TERMINATOR
};

typedef enum {
	OVL_SYMBOL_BITMAP = 1,
	OVL_SYMBOL_TEXT,
	OVL_SYMBOL_LINE,
	OVL_SYMBOL_POLYGON,
	OVL_SYMBOL_RECTANGLE,
	OVL_SYMBOL_CIRCLE,
	OVL_SYMBOL_TRIANGLE
} OVL_SYMBOL_TYP;

typedef enum {
	OVL_COLOR_RED = 1,	/* = 1 */
	OVL_COLOR_LIME,		/* = 2 */
	OVL_COLOR_BLUE,		/* = 3 */
	OVL_COLOR_YELLOW,	/* = 4 */
	OVL_COLOR_BLACK,	/* = 5 */
	OVL_COLOR_WHITE,	/* = 6 */
	OVL_COLOR_7,		/* = 7 (draws only a simple line) */
	OVL_COLOR_FUCHSIA,	/* = 8 */
	OVL_COLOR_AQUA,		/* = 9 */
} OVL_COLOR_TYP;

/* some hints:
		# "col":   color
		# "group": 1 means NO GROUP
		# "size":  size in pixels PLUS 100
		# "with":
		# "zoom":
		# "art":   line-style
 */
static inifile_t *inifile;
static gbfile *fout;

static int symbol_ct;	/* Number of symbols written */
static int group_ct;	/* Group number during write */
static int track_ct, route_ct;
static bounds all_bounds;
static OVL_COLOR_TYP color;

/*******************************************************************************
* %%%        global callbacks called by gpsbabel main process              %%% *
*******************************************************************************/

static void
ggv_ovl_rd_init(const char *fname)
{
	inifile = inifile_init(fname, MYNAME);
	if (inifile->unicode) cet_convert_init(CET_CHARSET_UTF8, 1);

	route_ct = 0;
	track_ct = 0;
}

static void 
ggv_ovl_rd_deinit(void)
{
	inifile_done(inifile);
}

static void
ggv_ovl_read(void)
{
	int symbols;
	int i;
		
	symbols = inifile_readint_def(inifile, "Overlay", "Symbols", -1);
	
	for (i = 1; i <= symbols; i++) {
		int points;
		OVL_SYMBOL_TYP type;
		char symbol[32];
		
		snprintf(symbol, sizeof(symbol), "Symbol %d", i);

		type = (OVL_SYMBOL_TYP) inifile_readint_def(inifile, symbol, "Typ", 0);
		points = inifile_readint_def(inifile, symbol, "Punkte", -1);
		
		switch(type) {
		
			char coord[32];
			waypoint *wpt;
			char *cx;
			int group;
			
			case OVL_SYMBOL_LINE:
			case OVL_SYMBOL_POLYGON:
			
				if (!inifile_readint(inifile, symbol, "Group", &group)) group = -1;

				if (points > 0) {
					int j;
					route_head *rte, *trk;
					
					rte = trk = route_head_alloc();
					if (group > 1) {
						route_add_head(rte);
						route_ct++;
						xasprintf(&rte->rte_name, "Route %d", route_ct);
					}
					else {
						track_add_head(trk);
						track_ct++;
						xasprintf(&trk->rte_name, "Track %d", track_ct);
					}
					
					for (j = 0; j < points; j++) {
						
						wpt = waypt_new();
						
						snprintf(coord, sizeof(coord), "YKoord%d", j);
						if ((cx = inifile_readstr(inifile, symbol, coord)))
							wpt->latitude = atof(cx);
						else
							continue;

						snprintf(coord, sizeof(coord), "XKoord%d", j);
						if ((cx = inifile_readstr(inifile, symbol, coord)))
							wpt->longitude = atof(cx);
						else
							continue;

						if (group > 1) route_add_wpt(rte, wpt);
						else track_add_wpt(trk, wpt);
					}
				}
				break;
				
			case OVL_SYMBOL_CIRCLE:
			case OVL_SYMBOL_TRIANGLE:

				wpt = waypt_new();
				wpt->shortname = xstrdup(symbol);
				
				if ((cx = inifile_readstr(inifile, symbol, "YKoord")))
					wpt->latitude = atof(cx);
				else
					continue;
				if ((cx = inifile_readstr(inifile, symbol, "XKoord")))
					wpt->longitude = atof(cx);
				else
					continue;

				waypt_add(wpt);		
				break;
				
			case OVL_SYMBOL_BITMAP:
			case OVL_SYMBOL_TEXT: 
			case OVL_SYMBOL_RECTANGLE: break;
		}
	}
}

/**************************************************************************/

/* prototypes used in main functions */

static void waypt_disp_cb(const waypoint *wpt);
static void track_disp_cb(const route_head *trk);
static void route_disp_cb(const route_head *rte);
static void write_bounds(void);
static void draw_symbol_basics(const OVL_SYMBOL_TYP typ, const int art, const OVL_COLOR_TYP color, const waypoint *wpt);
static int get_direction(const waypoint *A, const waypoint *B);
// static void draw_symbol_text(const char *text, const waypoint *reference);

/* -----------------------------------------------------------------------*/

static void
ggv_ovl_wr_init(const char *fname)
{
	fout = gbfopen(fname, "w", MYNAME);
	
	symbol_ct = 0;
}

static void
ggv_ovl_wr_deinit(void)
{
	gbfclose(fout);
}

static void
ggv_ovl_write(void)
{
	group_ct = 1;	/* tracks are not grouped */
	color = OVL_COLOR_FUCHSIA;
	track_disp_all(track_disp_cb, NULL, NULL);

	group_ct++;
	color = OVL_COLOR_AQUA;
	route_disp_all(route_disp_cb, NULL, NULL);

	group_ct++;
	color = OVL_COLOR_LIME;
	waypt_disp_all(waypt_disp_cb);

	gbfprintf(fout, "[Overlay]\n");
	gbfprintf(fout, "Symbols=%d\n", symbol_ct);
	gbfprintf(fout, "[MapLage]\n");
	gbfprintf(fout, "MapName=Bundesrepublik 1:1 Mio\n");
	gbfprintf(fout, "DimmFc=100\n");
	gbfprintf(fout, "ZoomFc=100\n");
	write_bounds();
	gbfprintf(fout, "RefOn=0\n");	/* no reference point */
}

/**************************************************************************/

static void
waypt_disp_cb(const waypoint *wpt)
{
	draw_symbol_basics(OVL_SYMBOL_CIRCLE, 1, color, wpt);
	gbfprintf(fout, "Width=20\n");
	gbfprintf(fout, "Height=20\n");
	gbfprintf(fout, "Dir=100\n");
	gbfprintf(fout, "Zoom=1\n");
	gbfprintf(fout, "Size=102\n");
	gbfprintf(fout, "Area=2\n");
//	draw_symbol_text(wpt->shortname, wpt);
}

/* -----------------------------------------------------------------------*/

static void
track_disp_cb(const route_head *trk)
{
	int i;
	queue *elem, *tmp;
	int waypt_ct = trk->rte_waypt_ct;
	
	if (waypt_ct <= 0) return;

	draw_symbol_basics(OVL_SYMBOL_LINE, 1, color, NULL);

	gbfprintf(fout, "Zoom=1\n");
	gbfprintf(fout, "Size=105\n");
	gbfprintf(fout, "Punkte=%d\n", waypt_ct);
	
	i = 0;
	
	QUEUE_FOR_EACH(&(trk->waypoint_list), elem, tmp) {

		waypoint *wpt = (waypoint *) elem;
		
		gbfprintf(fout, "XKoord%d=%0.8f\n", i, wpt->longitude);
		gbfprintf(fout, "YKoord%d=%0.8f\n", i, wpt->latitude);
		
		i++;
	}
}

/* -----------------------------------------------------------------------*/

static void
route_disp_cb(const route_head *rte)
{
	int i;
	queue *elem, *tmp;
	waypoint *prev;
	int waypt_ct = rte->rte_waypt_ct;
	
	if (waypt_ct <= 0) return;

	track_disp_cb(rte);	/* draw a line as tracks */

	color = OVL_COLOR_RED;
	
	i = 0;
	prev = NULL;
	
	QUEUE_FOR_EACH(&(rte->waypoint_list), elem, tmp) {

		waypoint *wpt = (waypoint *) elem;
		
		if (prev != NULL) {
			draw_symbol_basics(OVL_SYMBOL_TRIANGLE, 1, 9 /* color */, prev);

			gbfprintf(fout, "Width=12\n");
			gbfprintf(fout, "Height=8\n");
			gbfprintf(fout, "Dir=%d\n", 100 + get_direction(prev, wpt));
			gbfprintf(fout, "Zoom=1\n");
			gbfprintf(fout, "Size=101\n");
			gbfprintf(fout, "Area=2\n");
		}
		
		i++;
		prev = wpt;
	}
}

/* -----------------------------------------------------------------------*/

static void
waypt_bound_calc(const waypoint *waypointp)
{
	waypt_add_to_bounds(&all_bounds, waypointp);
}

static void
write_bounds(void)
{
	waypt_init_bounds(&all_bounds);

	waypt_disp_all(waypt_bound_calc);
	route_disp_all(NULL, NULL, waypt_bound_calc);
	track_disp_all(NULL, NULL, waypt_bound_calc);

	if (waypt_bounds_valid(&all_bounds)) {

		double cx = all_bounds.min_lat + ((all_bounds.max_lat - all_bounds.min_lat) / 2);
		double cy = all_bounds.min_lon + ((all_bounds.max_lon - all_bounds.min_lon) / 2);

		gbfprintf(fout, "CenterLat=%0.8f\n", cx);
		gbfprintf(fout, "CenterLong=%0.8f\n", cy);
	}
	else {
		gbfprintf(fout, "CenterLong=10.52374295\n");
		gbfprintf(fout, "CenterLat=52.26474445\n");
	}
}

static void
draw_symbol_basics(const OVL_SYMBOL_TYP typ, const int art, const OVL_COLOR_TYP color, const waypoint *wpt)
{
	symbol_ct++;
	
	gbfprintf(fout, "[Symbol %d]\n", symbol_ct);
	gbfprintf(fout, "Typ=%d\n", typ);
	gbfprintf(fout, "Group=%d\n", group_ct);
	gbfprintf(fout, "Col=%d\n", color);
	if (art >= 0) gbfprintf(fout, "Art=%d\n", art);
	if (wpt) {
		gbfprintf(fout, "XKoord=%.8f\n", wpt->longitude);
		gbfprintf(fout, "YKoord=%.8f\n", wpt->latitude);
	}
}

/* the following code comes from first overlay module */

static int
get_direction(const waypoint *A, const waypoint *B)
{
	double lata, lona, latb, lonb;
	double dist, dir;
	int res;
	
	lata = RAD(A->latitude);
	lona = RAD(A->longitude);
	latb = RAD(B->latitude);
	lonb = RAD(B->longitude);
	
	dist = gcdist(lata, lona, latb, lonb);
	dir = acos((sin(latb) - sin(lata) * cos(dist)) / (cos(lata) * sin(dist)));
	if (lonb < lona) dir = -dir;
	res = (int) DEG(dir);
	res = 360 - (res + 270);
	if (res < 0) res += 360;
	else if (res > 360) res -= 360.0;
	
	return res;
}

#if 0
static void
draw_symbol_text(const char *text, const waypoint *reference)
{
	waypoint wpt;
	
	if ((reference == NULL) || (text == NULL)) return;
	if (*text == '\0') return;
	
	wpt = *reference;
	
	wpt.latitude = wpt.latitude + 0.015;
	wpt.longitude = wpt.longitude + 0.015;
	
	draw_symbol_basics(OVL_SYMBOL_TEXT, -1, OVL_COLOR_BLACK, &wpt);

	gbfprintf(fout, "Area=1\n");
	gbfprintf(fout, "Zoom=1\n");
	gbfprintf(fout, "Size=120\n");
	gbfprintf(fout, "Font=3\n");
	gbfprintf(fout, "Dir=100\n");
	gbfprintf(fout, "Text=%s\n", text);
}
#endif

/**************************************************************************/

ff_vecs_t ggv_ovl_vecs = {
	ff_type_file,
	FF_CAP_RW_ALL,
	ggv_ovl_rd_init,	
	ggv_ovl_wr_init,	
	ggv_ovl_rd_deinit,	
	ggv_ovl_wr_deinit,	
	ggv_ovl_read,
	ggv_ovl_write,
	NULL,
	ggv_ovl_args,
	CET_CHARSET_MS_ANSI, 0
};

/**************************************************************************/
